package main

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"time"
	
	"github.com/davecgh/go-spew/spew"
	"github.com/gorilla/mux"
	"github.com/joho/godotenv"
	"strconv"
	"sync"
)


type Block struct {
	Index int // 索引
	Timestamp string // 时间戳
	BPM int  // 一分钟心跳的频率
	Hash string // 哈希
	PrevHash string // 前一个哈希
}

var Blockchain []Block  // 区块链

type Message struct {
	BPM int
}

var mutex = &sync.Mutex{} // 用于确保线程安全的Lock

func calculateHash(block Block) string {
	// strconv.Iota 将整数转换为十进制字符串形式
	record := strconv.Itoa(block.Index)

	h := sha256.New()       // 创建一个Hash对象
	h.Write([]byte(record)) // h.Write写入需要hash的内容
	hashed := h.Sum(nil)    // h.Sum 添加额外的[]byte到当前的哈希中
	return hex.EncodeToString(hashed)

	}


func genarateBlock(oldBlock Block, BPM int) (Block, error) {
	var newBlock Block
	t := time.Now()

	newBlock.Index = oldBlock.Index+1
	newBlock.Timestamp = t.String()
	newBlock.BPM = BPM
	newBlock.PrevHash = oldBlock.Hash
	newBlock.Hash = calculateHash(newBlock)

	return newBlock, nil //
	}
// 校验块，是否被篡改
func isBlockValid(newBlock Block, oldBlock Block) bool {
	if newBlock.Index != oldBlock.Index+1 {
		return false
	}
	if newBlock.PrevHash != oldBlock.Hash {
		return false
	}
	if calculateHash(newBlock) != newBlock.Hash {
		return false
	}
	return true
}

// 确定主链
func replaceChain(newBlock []Block) {
	if len(newBlock) > len(Blockchain) {
		Blockchain = newBlock
	}
}

// 构建webserver
//     设置路由
func makeMuxRouter() http.Handler  {
	muxRouter := mux.NewRouter()
	muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
	muxRouter.HandleFunc("/new", handleWriteBlock).Methods("GET")
	return muxRouter
}

//      定义Message

func handleGetBlockchain(w http.ResponseWriter, r *http.Request) {
	//        格式化输出josn
	bytes, err := json.MarshalIndent(Blockchain, "", "\t")
	
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return 
	}
	io.WriteString(w, string(bytes))
}

//响应json格式化封装
func respondWithJson(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
	response, err := json.MarshalIndent(payload, "", "\t")
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)         //响应错误状态码
		w.Write([]byte("HTTP 500: Internal Server Error"))    //响应错误内容
		return
	}
	w.WriteHeader(code)
	w.Write(response)
}

//     创建新的区块， 并返回创建的信息
func handleWriteBlock(w http.ResponseWriter, r *http.Request)  {
	w.Header().Set("Content-Type", "application/json")
	var m Message

	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(&m); err != nil {
		respondWithJson(w, r, http.StatusBadRequest, r.Body)
		return
	}
	defer r.Body.Close()

	oldBlock := Blockchain[len(Blockchain)-1]
	mutex.Lock()
	newBlock, err := genarateBlock(oldBlock, m.BPM)
	if err != nil {
		log.Println("[error] new Block create failed", err.Error())
	}
	mutex.Unlock()

	if isBlockValid(newBlock, oldBlock) {
		Blockchain = append(Blockchain, newBlock)
		spew.Dump(Blockchain)
	}

	respondWithJson(w, r, http.StatusCreated, newBlock)
}

func run() error {
	mux := makeMuxRouter()  // 编写路由
	
	httpAddr := os.Getenv("PORT")
	log.Println("[INFO] Listening on", os.Getenv("PORT"))
	s := &http.Server{
		Addr: ":" + httpAddr,
		Handler: mux,
		ReadTimeout: time.Second * 10,
		WriteTimeout: time.Second * 10,
		MaxHeaderBytes: 1 << 20,
	}
	
	if err := s.ListenAndServe(); err != nil {
		return err
	}
	return nil
	}
	
// 主程序
func main() {
	err := godotenv.Load("prop.env")  // 读取根目录中　．ｅｎｖ　文件
	if err != nil {
		log.Fatal(err)
	}
	
	go func() {
		t := time.Now()
		genesisBlock := Block{}   // 创始块的创建，　第一个块的生成
		
		genesisBlock = Block{0, t.String(), 0, calculateHash(genesisBlock), ""}
		spew.Dump(genesisBlock)
		
		mutex.Lock()
		Blockchain = append(Blockchain, genesisBlock)
		mutex.Unlock()
	}()
	log.Fatal(run())
}